package core;

import channel.*;
import demodulation.*;
import demodulation.Digitizer;
import demodulation.Integrator;
import demodulation.Multiplier;
import helper.Rectifier;
import helper.BERCounter;
import helper.BinaryNumber;
import helper.MessageAndSignalHandler;
import jxl.write.WriteException;
import modulation.ModulatorController;
import modulation.ModulatorSignal;

import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: Eugene
 * Date: 12/15/12
 * Time: 10:30 PM
 * To change this template use File | Settings | File Templates.
 */
public class DataFlow {
    public static void main(String[] args) throws WriteException {

        //input message generating
        String inputMessage = MessageAndSignalHandler.generateRandomBitsString(512);

        //transformation of String message to ArrayList of Binary Numbers
        List<BinaryNumber> sourceSymbols = MessageAndSignalHandler.stringToBinaryNumbers(inputMessage, 8);

        Double informationalSpeed = 900.0;

        //speed variation loop
        Double carrierFrequency = 1000.0;
        Double sourceImpulseLength = 1 / informationalSpeed;
        Double carrierAmplitude = 10.0;

        Double amplitudeMultiplier = 0.0;
        Double timeShift = 0.0;

        ModulatorController currentModulator;
        currentModulator = new ModulatorController(ModulatorController.ModulationType.ASK, carrierAmplitude, carrierFrequency, 0, sourceSymbols, sourceImpulseLength);

        List<ModulatorSignal> modulatorData;
        List<PropagatorSignal> delayedData;
        modulatorData = currentModulator.getSignals();

        Propagator propagator = new Propagator(modulatorData, amplitudeMultiplier, timeShift);
        delayedData = propagator.delayedSequence;

        Double noisePower = 1.0;

        NoiseGenerator currentNoiseGenerator;
        currentNoiseGenerator = new NoiseGenerator(modulatorData, noisePower);

        List<NoiseSignal> noiseSignals;
        noiseSignals = currentNoiseGenerator.getSignals();

        Channel currentChannel;
        List<ChannelSignal> channelOutput;

        currentChannel = new Channel(modulatorData, noiseSignals);
        currentChannel.setDelayedModulatorSignals(delayedData);

        channelOutput = currentChannel.getSignals();

        ReferenceGenerator currentReferenceGenerator0, currentReferenceGenerator1;
        List<ModulatorSignal> referenceGenerator0Output;
        List<ModulatorSignal> referenceGenerator1Output;
        Multiplier currentMultiplier0, currentMultiplier1;
        List<MultiplierSignal> multiplier0Output;
        List<MultiplierSignal> multiplier1Output;
        Digitizer currentDigitizer0, currentDigitizer1;
        Integrator currentIntegrator0, currentIntegrator1;
        Summator currentSummator;
        Resolver currentResolver;
        List<DigitalSignal> digitizer0Output;
        List<DigitalSignal> digitizer1Output;
        List<DigitalSignal> integrator0Output;
        List<DigitalSignal> integrator1Output;
        List<DigitalSignal> summatorOutput;
        List<BinaryNumber> resolverOutput;
        currentReferenceGenerator0 = new ReferenceGenerator(carrierFrequency, 0, 0, channelOutput);
        currentReferenceGenerator1 = new ReferenceGenerator(carrierFrequency, carrierAmplitude, 0, channelOutput);
        referenceGenerator0Output = currentReferenceGenerator0.getSignals();
        referenceGenerator1Output = currentReferenceGenerator1.getSignals();
        currentMultiplier0 = new Multiplier(channelOutput, referenceGenerator0Output);
        currentMultiplier1 = new Multiplier(channelOutput, referenceGenerator1Output);
        multiplier0Output = currentMultiplier0.getSignals();
        multiplier1Output = currentMultiplier1.getSignals();

        double end = multiplier0Output.get(multiplier0Output.size() - 1).getEnd();
        double step = 1 / (3 * carrierFrequency);
        currentDigitizer0 = new Digitizer(multiplier0Output, step);
        currentDigitizer1 = new Digitizer(multiplier1Output, step);
        digitizer0Output = currentDigitizer0.getDigitalSignal();
        digitizer1Output = currentDigitizer1.getDigitalSignal();

        currentIntegrator0 = new Integrator(digitizer0Output);
        currentIntegrator1 = new Integrator(digitizer1Output);
        integrator0Output = currentIntegrator0.getIntegrals();
        integrator1Output = currentIntegrator1.getIntegrals();

        currentSummator = new Summator(integrator0Output, integrator1Output);
        summatorOutput = currentSummator.getSum();

        double threshold;

        double w = 2 * Math.PI * carrierAmplitude;
        threshold = -0.25 * (Math.pow(carrierAmplitude, 2) * (Math.cos(w * sourceImpulseLength) * Math.sin(w * sourceImpulseLength) - w * sourceImpulseLength)) / w;
        List<Integer> lengthMap = new ArrayList<Integer>();
        for (BinaryNumber bn : sourceSymbols) {
            lengthMap.add(bn.getLength());
        }
        currentResolver = new Resolver(summatorOutput, threshold, lengthMap, sourceSymbols);
        resolverOutput = currentResolver.getBinaryNumbers();


        List<Boolean> sourceBits = new ArrayList<Boolean>();
        List<Boolean> resolverBits = new ArrayList<Boolean>();
        sourceBits = Rectifier.getBits(sourceSymbols);
        resolverBits = Rectifier.getBits(resolverOutput);

        Double BER = BERCounter.calculateBER(resolverBits, sourceBits);
        System.out.println(BER);
    }

}